/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 文件名：	BOptionMgr.java
 * 模块说明：	
 * 修改历史：
 * 2007-3-20 - lxm - 创建。
 */
package com.hd123.rumba.option.biz;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Transaction;

import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.domain.IDomainMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.option.COptionCollection;
import com.hd123.rumba.option.IOptionCollection;
import com.hd123.rumba.option.IOptionItem;
import com.hd123.rumba.option.IOptionMgr;
import com.hd123.rumba.option.IOptionalClassInfo;
import com.hd123.rumba.option.IOptionalClassInfoMgr;
import com.hd123.rumba.runtime.IManager;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.runtime.biz.BManager;
import com.hd123.rumba.runtime.biz.BPersistent;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.user.IUserMgr;
import com.hd123.rumba.util.ClassifiedHashtable;

/**
 * 选项 | 业务层 | 管理员 | 实现类
 * 
 * @author lxm
 * 
 */
public class BOptionMgr extends BManager implements IBOptionMgr {

  @Override
  public IManager getPerzMgr() throws BusinessException {
    return getOptMgr();
  }

  public void registerClassInfoT(Class optionalClass, Integer individuation, Boolean locked,
      Boolean online) throws BusinessException, HibernateException {
    this.checkParameterNotNull(optionalClass, "optionaClass");
    this.checkParameterNotNull(individuation, "individuation");
    this.checkParameterNotNull(locked, "locked");
    this.checkParameterNotNull(online, "online");

    IOptionalClassInfo classInfo = getClassInfoMgr().getClassInfoByClass(optionalClass.getName());
    if (classInfo == null) {
      classInfo = getClassInfoMgr().createClassInfo();
      classInfo.setOptionalClassName(optionalClass.getName());
    }
    classInfo.setIndividuation(individuation);
    classInfo.setLocked(locked);
    classInfo.setOnline(online);

    Transaction tx = getSession().beginTransaction();
    try {
      getClassInfoMgr().saveClassInfo(classInfo);
      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      if (e instanceof HibernateException)
        throw (HibernateException) e;
      else
        throw new BusinessException(e);
    } finally {
      getSession().flush();
    }
  }

  public void unregisterClassInfoT(Class optionalClass) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(optionalClass, "optionalClass");

    IOptionalClassInfo classInfo = getClassInfoMgr().getClassInfoByClass(optionalClass.getName());

    Transaction tx = getSession().beginTransaction();
    try {
      getClassInfoMgr().removeClassInfo(classInfo);
      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      if (e instanceof HibernateException)
        throw (HibernateException) e;
      else
        throw new BusinessException(e);
    } finally {
      getSession().flush();
    }
  }

  public BOptionCollection createCollection(String domainUuid, String optionalClassName,
      String userUuid) throws BusinessException, HibernateException {
    this.checkParameterNotNull(domainUuid, "domainUuid");
    this.checkParameterNotNull(optionalClassName, "optionalClassName");

    IDomain domain = getDomainMgr().getDomain(domainUuid);
    IUser user = null;
    if (userUuid != null)
      user = getUserMgr().getUser(userUuid);
    return this.createCollection(domain, optionalClassName, user);
  }

  public BOptionCollection createCollection(IDomain domain, String optionalClassName, IUser user)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(optionalClassName, "optionalClassName");
    IOptionCollection perz = getOptMgr().createCollection(domain, optionalClassName, user);
    BOptionCollection biz = null;
    try {
      biz = (BOptionCollection) Class.forName(optionalClassName).newInstance();
    } catch (InstantiationException e) {
      throw new BusinessException(e);
    } catch (IllegalAccessException e) {
      throw new BusinessException(e);
    } catch (ClassNotFoundException e) {
      biz = new BOptionCollection();
    }
    biz.readFrom(perz);
    return biz;
  }

  public <O extends BOptionCollection> O createCollection(String domainUuid, Class<O> optionClass,
      String userUuid) throws BusinessException, HibernateException {
    this.checkParameterNotNull(domainUuid, "domainUuid");
    this.checkParameterNotNull(optionClass, "optionClass");

    IDomain domain = getDomainMgr().getDomain(domainUuid);
    IUser user = null;
    if (userUuid != null)
      user = getUserMgr().getUser(userUuid);
    return this.createCollection(domain, optionClass, user);
  }
  
  public <O extends BOptionCollection> O createCollection(IDomain domain, Class<O> optionClass,
      IUser user) throws BusinessException, HibernateException {
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(optionClass, "optionClass");
    return (O) this.createCollection(domain, optionClass.getName(), user);
  }
  
  public BOptionCollection loadCollection(String uuid) throws BusinessException, HibernateException {
    return (BOptionCollection) this.getCollection(uuid, BOptionCollection.class);
  }

  public <O extends BOptionCollection> O loadCollection(IDomain domain,
      Class<O> optionClass, IUser user) throws BusinessException, HibernateException {
    return this.getCollectionByClass(domain, optionClass.getName(), user, optionClass);
  }

  public BOptionCollection loadCollection(IDomain domain, String optionalClassName, IUser user)
      throws BusinessException, HibernateException {
    return this.getCollectionByClass(domain, optionalClassName, user, BOptionCollection.class);
  }

  public <O extends BOptionCollection> O loadCollection(String domainUuid,
      Class<O> optionClass, String userUuid) throws BusinessException, HibernateException {
    return this.getCollectionByClass(domainUuid, optionClass.getName(), userUuid, optionClass);
  }

  public BOptionCollection loadCollection(String domainUuid,
      String optionalClassName, String userUuid) throws BusinessException, HibernateException {
    return this.getCollectionByClass(domainUuid, optionalClassName, userUuid,
        BOptionCollection.class);
  }

  public ClassifiedHashtable saveCollection(BOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");

    IOptionCollection perz = createOrLoadCollection(collection);
    ClassifiedHashtable h = verifyToSaveCollection(collection, perz);
    if (h != null)
      return h;
    writeToCollection(collection, perz);

    getOptMgr().saveCollection(perz, operate);

    collection.readFrom(perz);
    return null;
  }

  public ClassifiedHashtable clearCollection(BOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");

    IOptionCollection perz = createOrLoadCollection(collection);
    ClassifiedHashtable h = this.checkOca(perz, collection.getOca(),
        COptionCollection.CAPTION_CLASS, perz.toBizString());
    if (h != null)
      return h;

    perz.setInherited(Boolean.TRUE);
    perz.getItems().clear();

    getOptMgr().saveCollection(perz, operate);

    collection.readFrom(perz);
    return null;
  }

  public ClassifiedHashtable lockCollection(BOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");

    IOptionCollection perz = createOrLoadCollection(collection);
    ClassifiedHashtable h = this.checkOca(perz, collection.getOca(),
        COptionCollection.CAPTION_CLASS, perz.toBizString());
    if (h != null)
      return h;
    h = this.verifyGlobalCollection(collection);
    if (h != null)
      return h;

    perz.setLocked(Boolean.TRUE);
    getOptMgr().saveCollection(perz, operate);

    collection.readFrom(perz);
    return null;
  }

  public ClassifiedHashtable unlockCollection(BOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");

    IOptionCollection perz = createOrLoadCollection(collection);
    ClassifiedHashtable h = this.checkOca(perz, collection.getOca(),
        COptionCollection.CAPTION_CLASS, perz.toBizString());
    if (h != null)
      return h;
    h = this.verifyGlobalCollection(collection);
    if (h != null)
      return h;

    perz.setLocked(Boolean.FALSE);
    getOptMgr().saveCollection(perz, operate);

    collection.readFrom(perz);
    return null;
  }

  public ClassifiedHashtable offlineCollection(BOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");

    IOptionCollection perz = createOrLoadCollection(collection);
    ClassifiedHashtable h = this.checkOca(perz, collection.getOca(),
        COptionCollection.CAPTION_CLASS, perz.toBizString());
    if (h != null)
      return h;
    h = this.verifyGlobalCollection(collection);
    if (h != null)
      return h;

    perz.setOnline(Boolean.FALSE);
    getOptMgr().saveCollection(perz, operate);

    collection.readFrom(perz);
    return null;
  }

  public ClassifiedHashtable onlineCollection(BOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");

    IOptionCollection perz = createOrLoadCollection(collection);
    ClassifiedHashtable h = this.checkOca(perz, collection.getOca(),
        COptionCollection.CAPTION_CLASS, perz.toBizString());
    if (h != null)
      return h;
    h = this.verifyGlobalCollection(collection);
    if (h != null)
      return h;

    perz.setOnline(Boolean.TRUE);
    getOptMgr().saveCollection(perz, operate);

    collection.readFrom(perz);
    return null;
  }

  public <O extends BPersistent> O getCollection(String uuid, Class<O> bizClass)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(uuid, "uuid");
    this.checkParameterNotNull(bizClass, "bizClass");
    IOptionCollection perz = getOptMgr().getCollection(uuid);
    O biz = (O) this.createBizClass(bizClass);
    biz.readFrom(perz);
    return biz;
  }

  public <O extends BPersistent> O getCollectionByClass(String domainUuid,
      String optionalClassName, String userUuid, Class<O> bizClass) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(domainUuid, "domainUuid");
    this.checkParameterNotNull(optionalClassName, "optionalClassName");
    this.checkParameterNotNull(bizClass, "bizClass");
    IDomain domain = getDomainMgr().getDomain(domainUuid);
    IUser user = null;
    if (userUuid != null)
      user = getUserMgr().getUser(userUuid);
    return this.getCollectionByClass(domain, optionalClassName, user, bizClass);
  }

  public <O extends BPersistent> O getCollectionByClass(IDomain domain, String optionalClassName,
      IUser user, Class<O> bizClass) throws BusinessException, HibernateException {
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(optionalClassName, "optionalClassName");
    this.checkParameterNotNull(bizClass, "bizClass");
    IOptionCollection perz = getOptMgr().getCollectionByClass(domain, optionalClassName, user);
    if (perz == null)
      return null;
    O biz = (O) this.createBizClass(bizClass);
    biz.readFrom(perz);
    return biz;
  }

  private IOptionalClassInfoMgr classInfoMgr = null;
  private IOptionMgr optMgr = null;
  private IDomainMgr domainMgr = null;
  private IUserMgr userMgr = null;

  private IOptionMgr getOptMgr() throws BusinessException {
    if (optMgr == null)
      optMgr = (IOptionMgr) NamingMgr.getInstance().lookupMgr(IOptionMgr.class);
    return optMgr;
  }

  private IOptionalClassInfoMgr getClassInfoMgr() throws BusinessException {
    if (classInfoMgr == null)
      classInfoMgr = (IOptionalClassInfoMgr) NamingMgr.getInstance().lookupMgr(
          IOptionalClassInfoMgr.class);
    return classInfoMgr;
  }

  private IDomainMgr getDomainMgr() throws BusinessException {
    if (domainMgr == null)
      domainMgr = (IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class);
    return domainMgr;
  }

  private IUserMgr getUserMgr() throws BusinessException {
    if (userMgr == null)
      userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    return userMgr;
  }

  private IOptionCollection createOrLoadCollection(BOptionCollection biz) throws BusinessException,
      HibernateException {
    IOptionCollection perz = null;
    if (biz.getUuid() == null) {
      IDomain domain = getDomainMgr().getDomain(biz.getDomain().getUuid());
      IUser user = null;
      if (biz.getUser() != null)
        user = getUserMgr().getUser(biz.getUser().getUuid());
      perz = getOptMgr().createCollection(domain, biz.getOptionalClassName(), user);
    } else
      perz = getOptMgr().getCollection(biz.getUuid());
    return perz;
  }

  private ClassifiedHashtable verifyToSaveCollection(BOptionCollection biz, IOptionCollection perz)
      throws BusinessException, HibernateException {
    ClassifiedHashtable h = this.checkOca(perz, biz.getOca(), COptionCollection.CAPTION_CLASS, biz
        .toBizString());
    if (h != null)
      return h;

    h = new ClassifiedHashtable();
    IDomain domain = getDomainMgr().getDomain(biz.getDomain().getUuid());
    IUser user = null;
    if (biz.getUser() != null)
      user = getUserMgr().getUser(biz.getUser().getUuid());
    IOptionCollection perz2 = getOptMgr().getCollectionByClass(domain, biz.getOptionalClassName(),
        user);
    if (perz2 != null && !perz2.getUuid().equals(biz.getUuid()))
      h.putMessage("collection", ClassifiedHashtable.ERROR, "已经存在相同业务主键的"
          + COptionCollection.CAPTION_CLASS + "(" + perz.toBizString() + ")。");

    return h.size() > 0 ? h : null;
  }

  private void writeToCollection(BOptionCollection biz, IOptionCollection perz)
      throws BusinessException, HibernateException {
    if (biz.getUser() == null)
      biz.refreshGlobalSetting();
    perz.setLocked(biz.locked);
    perz.setOnline(biz.online);
    perz.setInherited(biz.getInherited());
    
    for (int i = perz.getItems().size() - 1; i >= 0; i--) {
      IOptionItem pitem = perz.getItems().get(i);
      getOptMgr().removeItemFromCollection(perz, pitem);
    }
    
    Object[] names = biz.getValues().keySet().toArray();
    for (int i = 0; i < names.length; i++) {
      String name = (String) names[i];
      Object value = biz.getValues().get(name);
      IOptionItem pitem = getOptMgr().createItem(perz);
      pitem.setName(name);
      pitem.setValue(value);
      getOptMgr().addItemToCollection(perz, pitem);
    }
  }

  private ClassifiedHashtable verifyGlobalCollection(BOptionCollection biz)
      throws BusinessException, HibernateException {
    ClassifiedHashtable h = new ClassifiedHashtable();
    if (biz.getUser() != null)
      h.putMessage("collection", ClassifiedHashtable.ERROR, "指定的操作仅适用于全局取值。");
    return h.size() > 0 ? h : null;
  }
}
